import { Context, Next } from "koa"
import { GameStage } from "../constant/GameStage"
import { Poker } from "../data/Poker"
import Room from "../data/Room"
import RoomManager from "../game/RoomManager"
import GameNotifier from "../websocket/GameNotifier"

let taskTimer: NodeJS.Timeout | null = null

export default class GameController {
  // 有人准备
  static async prepare(ctx: Context, next: Next) {
    // 获取参数...
    const { uid, roomId, isPrepare }: { uid: string, roomId: string, isPrepare: boolean } = ctx.request.body

    const room: Room = RoomManager.instance.getRoomByRoomId(roomId)
    // console.log('room:', room)

    // 不是准备阶段不能执行
    if (room.referee.stage != GameStage.PREPARATION) {
      ctx.err({
        message: 'not in the preparation stage'
      })
      return
    }

    // 设定该房间的人进行准备
    room.setUserPrepare(uid, isPrepare)

    // socket emit
    GameNotifier.instance.sendPrepare(uid, room.id, isPrepare)

    // 判断是否全部准备，并开始游戏
    if (room.isAllPrepare()) {
      console.log('[game] all prepare')
      // 初始化裁判数据
      room.referee.init(room.players)
      // 监听游戏阶段
      room.referee.addStageListener((stage: GameStage) => {
        // socket emit 通知客户端阶段改变
        GameNotifier.instance.sendChangeGameStage(room.id, stage)
      })
      // 发牌
      room.referee.deal()
      // socket emit 发牌
      room.players.forEach(player => {
        if (player !== undefined) {
          GameNotifier.instance.sendDeal(player.id, player.cards)
        }
      })
      // 等待客户端理牌，并调用ready api
    }

    // 返回请求结果...
    ctx.result({
      code: 200,
      message: "prepare"
    })
  }

  // 客户端洗好牌
  static async ready(ctx: Context, next: Next) {
    // 获取参数...
    const { uid, roomId }: { uid: string, roomId: string } = ctx.request.body

    const room: Room = RoomManager.instance.getRoomByRoomId(roomId)

    // 不是发牌阶段不能执行
    if (room.referee.stage != GameStage.REFEREE_DEAL) {
      ctx.err({
        message: 'not in the deal stage'
      })
      return
    }

    room.setPlayerReady(uid)

    // 所有客户端都整理好牌
    if (room.isAllReady()) {
      console.log('room isAllReady')
      // 所有客户端都整理好牌
      // 正式开始游戏
      // 进入抢地主环节
      const firstPlayer = room.referee.initCallLandloard()
      // 告诉房间所有人，由谁开始叫地主
      GameNotifier.instance.sendSetCallPlayer(firstPlayer.id, room.id)

      // TODO: 定时功能
      // 轮流机制：获得当前回合的玩家的函数 ? 
      // 定时机制：每次轮到下一方操作都会开启一个定时器，定时执行取消
    }

    // 返回请求结果...
    ctx.result({
      code: 200,
      message: "ready"
    })
  }

  // 有人叫地主
  static async callLandlord(ctx: Context, next: Next) {
    // 获取参数...
    const { uid, roomId, isCall }: { uid: string, roomId: string, isCall: boolean } = ctx.request.body

    const room = RoomManager.instance.getRoomByRoomId(roomId)

    // 不是叫地主阶段不能执行
    if (room.referee.stage != GameStage.CALL_LANDLORD) {
      ctx.err({
        message: 'not in the call landlord stage'
      })
      return
    }

    // 校验是否是当前玩家的回合
    if (!room.referee.isRound(uid)) {
      ctx.err({
        message: "not the current player's round"
      })
      return
    }

    if (isCall) {
      // 叫地主
      room.referee.callLandloard(uid)
    }
    // socket emit 通知有人叫地主
    GameNotifier.instance.sendCallLandlord(uid, room.id, isCall)

    // 下一个叫地主的玩家
    const nextPlayer = room.referee.nextCallLandloardPlayer()
    if (nextPlayer) {
      // socket emit 通知下一个要叫地主的玩家
      GameNotifier.instance.sendSetCallPlayer(nextPlayer.id, room.id)
    } else {

      // nextPlayer为null表示没有下一个要叫地主的玩家了，结束叫地主环节
      // TODO: 结束定时功能
      // if (taskTimer) { clearTimeout(taskTimer) }

      room.referee.determineLandloard() // 确定地主

      // 判断叫地主阶段是否有人叫地主（若没有人叫地主，那么landlordPlayer为null）
      if (room.referee.landlordPlayer) {
        const landlordCards = room.referee.landlordCards  // 地主牌
        // socket emit 通知客户端 谁是地主，并发送地主牌
        GameNotifier.instance.sendSetLandlord(room.referee.landlordPlayer.id, room.id, landlordCards)
        // socket emit 通知客户端 由谁出牌
        GameNotifier.instance.sendSetPlay(room.referee.landlordPlayer.id, room.id)
      } else {
        // 没有地主（没人叫地主）
        // 重新发牌
        room.referee.deal()
        // socket emit 发牌
        room.players.forEach(player => {
          if (player !== undefined) {
            GameNotifier.instance.sendDeal(player.id, player.cards)
          }
        })

        // 重新进入抢地主环节
        const firstPlayer = room.referee.initCallLandloard()
        // 告诉房间所有人，由谁开始叫地主
        GameNotifier.instance.sendSetCallPlayer(firstPlayer.id, room.id)
      }
    }

    // TODO: 给下一个人定时

    // 返回请求结果...
    ctx.result({
      code: 200,
      message: "callLandlord"
    })
  }

  // 出牌
  static async playCards(ctx: Context, next: Next) {

    // 获取参数...
    const { uid, roomId, isPlay, cards }: { uid: string, roomId: string, isPlay: boolean, cards: Array<Poker> } = ctx.request.body

    const room = RoomManager.instance.getRoomByRoomId(roomId)
    // 不是叫出牌阶段不能执行
    if (room.referee.stage != GameStage.GAMING) {
      ctx.err({
        message: 'not in the gaming stage'
      })
      return
    }

    // 校验是否是当前玩家的回合
    if (!room.referee.isRound(uid)) {
      ctx.err({
        message: "not the current player's round"
      })
      return
    }

    // 判断用户是否出牌
    if (isPlay) {
      // 牌型校验+减少手牌
      room.referee.playCards(uid, cards)
      // socket emit 通知其他玩家有人出牌
      GameNotifier.instance.sendPlayCards(uid, room.id, true, cards)
    } else {
      // socket emit 通知其他玩家上家不出牌
      GameNotifier.instance.sendPlayCards(uid, room.id, false, cards)
    }

    // 获得下一个回合出牌的玩家
    const nextPlayer = room.referee.nextPlayCardPlayer()
    if (nextPlayer) {
      // socket emit 通知房间的玩家，轮到谁出牌
      GameNotifier.instance.sendSetPlay(nextPlayer.id, room.id)
    } else {
      // 游戏结束
      // 结算数据
      const result = room.referee.getResult()
      // socket emit 通知 游戏结果
      GameNotifier.instance.sendResult(room.id, result)
    }

    // 返回请求结果...
    ctx.result({
      code: 200,
      message: "playCards"
    })
  }
}